<?php

namespace app\common\storage;

use app\admin\model\StorageChunks;
use app\admin\model\StoragePath;
use app\common\tools\PathTools;
use app\common\tools\StorageTools;
use League\Flysystem\Adapter\Local;
use League\Flysystem\Filesystem;
use Overtrue\Flysystem\Qiniu\QiniuAdapter;
use Symfony\Component\Finder\Finder;
use think\facade\App;
use think\facade\Config;
use think\facade\Log;

class CommonStorage
{
    protected $flysystem = null;

    const CHUNK_SIZE_SET = 4096 * 1024;

    public function getFlysystem()
    {
        if (is_null($this->flysystem)) {

            // $accessKey = sysconfig('storage', 'storage_qnoss_access_key');
            // $secretKey = sysconfig('storage', 'storage_qnoss_secret_key');
            // $bucket = sysconfig('storage', 'storage_qnoss_bucket');
            // $domain = sysconfig('storage', 'storage_qnoss_domain');

            // $adapter = new QiniuAdapter($accessKey, $secretKey, $bucket, $domain);

            $project_path = App::getRootPath() . 'data/storage/uldisk/';

            PathTools::intiDir($project_path);

            $adapter = new Local($project_path);

            $flysystem = new Filesystem($adapter);

            $this->flysystem = $flysystem;
        }

        return $this->flysystem;
    }

    public function writeChunk($chunk_content, $sort)
    {

        // TODO:返回的chunk模型需要包含chunk_position的模型，这里面存储了chunk的信息
        $chunk_content_md5 = md5($chunk_content);

        $model_chunks = StorageChunks::where('storage_path_id', $this->modelPath->id)
            ->where('sort', $sort)
            ->find();


        if (!empty($model_chunks)) {
            if ($chunk_content_md5 == $model_chunks->chunk_md5) {
                // 当前数据块没有变化，跳过
                return $model_chunks;
            }

            // 当前数据变化了，删除之前的块

            $this->deleteChunk($model_chunks->chunk_md5);
        } else {
            $model_chunks = new StorageChunks();

            $model_chunks->storage_path_id = $this->modelPath->id;

            $model_chunks->sort = $sort;
        }

        $model_chunks->chunk_md5 = $chunk_content_md5;



        StorageTools::write($chunk_content, $chunk_content_md5);

        $model_chunks->save();
        return $model_chunks;
    }

    public function readChunk($chunk_md5)
    {


        $result = StorageTools::read($chunk_md5);
        return $result;
    }



    public function getFileTempPrefixPath()
    {
        $prefix_path = Config::get('storage.file_cache_path');

        PathTools::intiDir($prefix_path . 'temp');

        return $prefix_path;
    }

    public function buildFileTempPath($etag)
    {
        $prefix_path = $this->getFileTempPrefixPath();

        $file_path_md5 = $etag;

        $file_path_prefix = substr($file_path_md5, 0, 2);

        $file_name = substr($file_path_md5, 2);

        $file_path = $prefix_path . $file_path_prefix . '/' . $file_name . '.temp';


        PathTools::intiDir($file_path);

        return $file_path;
    }

    /**
     * 内部只进行了文件操作，没有进行chunk模型操作
     *
     * @param [type] $chunk_md5
     * @return void
     */
    public function deleteChunk($chunk_md5)
    {


        $chunk_count = StorageChunks::where('chunk_md5', $chunk_md5)->count();

        if ($chunk_count <= 1) {
            StorageTools::delete($chunk_md5);
        }
    }

    public static function write(StoragePath $model_path, $data)
    {
        return (new WriterStorage($model_path, $data))->save();
    }

    public static function patch(StoragePath $model_path, $data, $rangeType, $offset = null)
    {
        return (new WriterStorage($model_path, $data, $rangeType, $offset))->savePatch();
    }

    public static function read(StoragePath $model_path)
    {
        return (new ReaderStorage($model_path))->stream();
    }

    public static function readAsString(StoragePath $model_path)
    {
        return (new ReaderStorage($model_path))->string();
    }

    public function checkFreeSpace($need_space = 0)
    {

        $need_space *= 2;

        $file_temp = $this->getFileTempPrefixPath();

        // 检查磁盘剩余空间

        $free_space = disk_free_space($file_temp);

        if ($free_space > $need_space) {
            return true;
        }


        return false;
    }

    public function clearFileTemp($need_space = 0)
    {

        $need_space *= 2;

        $file_temp = $this->getFileTempPrefixPath();

        // 检查磁盘剩余空间

        $free_space = disk_free_space($file_temp);

        if ($free_space > $need_space) {
            return true;
        }


        $finder = new Finder();
        $finder->in($file_temp)->files();


        foreach ($finder as $file) {
            $last_access_time = $file->getATime();

            // 删除3天前的文件
            if (empty($last_access_time) || $last_access_time < time() - 86400 * 3) {
                if ($file->isWritable()) {
                    unlink($file->getRealPath());
                }
            }
        }

        // 如果空间还是不够，把时间最早的删除

        $free_space = disk_free_space($file_temp);

        if ($free_space > $need_space) {
            return true;
        }



        $finder->sortByAccessedTime()->reverseSorting();

        $delete_spance = 0;

        foreach ($finder as $file) {
            $last_access_time = $file->getATime();

            if ($last_access_time > time() - 1800) {
                // 半小时内访问过的不要删除
                continue;
            }


            if ($file->isWritable()) {
                $file_size = $file->getSize();
                unlink($file->getRealPath());
                $delete_spance += $file_size;
            }

            if ($free_space + $delete_spance > $need_space) {
                break;
            }
        }
    }
}
